import React, {Component, Fragment} from "react";
import TodoItem from "./TodoItem";
//一般先引用组件，后引用样式
import './style.css';

/**
 * react帮助我们完成了数据和页面的映射
 *
 * immutable：
 *      state不允许我们做任何的改变，实际修改list的时候，并没有修改state下面的list，而是修改list的一个副本。
 */
class TodoList extends Component {
    //当我们使用构造函数的时候，constructor是优于其他函数，是最先被执行的一个函数
    //接受props参数
    constructor(props) {
        //调用一次父类的构造函数
        super(props)
        //react里面定义数据需要把数据定义在状态里面,state负责存储组件中的数据
        this.state = {
            inputValue: '',
            list: []
        };
        this.handleInputChange = this.handleInputChange.bind(this);
        this.handleBtnClick = this.handleBtnClick.bind(this);
        this.handleItemDelete = this.handleItemDelete.bind(this);
    }

    //render组件函数定义返回的内容，外层必须有一个包裹元素
    //在React 16 以后的版本中，提供了一个 Fragment 的占位符,用Fragment替代最外层的div标签,可以让外层的标签隐藏掉
    render() {
        //不加括号也可可以，加了括号可以写多行
        return (
            <Fragment>
                <div>
                    {/*在html中，label的作用是扩大点击的区域*/}
                    <label htmlFor='insertArea'>输入内容</label>
                    {/*如果要使用js的表达式，要使用花括号对表达式进行包裹，事件绑定的时候要用bind(this)对函数的作用域进行变更*/}
                    {
                        //JSX中的注释写法
                    }
                    <input
                        id='insertArea'
                        value={this.state.inputValue}
                        // onChange 方法这么写，它的this指向是 underfined
                        // onChange={this.handleInputChange}/>
                        //使用bind 函数改变 onChange 函数中的this指向
                        onChange={this.handleInputChange}
                        className='input'
                    />
                    {/*在React里面绑定事件的时候，事件要满足驼峰命名*/}
                    <button onClick={this.handleBtnClick}>提交</button>
                </div>
                <ul>
                    {
                        this.getTodoItem()
                    }
                </ul>
            </Fragment>
        );
    }

    getTodoItem() {
        // 在ES6里面数组有一个map方法，通过map方法对list进行一个循环
        return this.state.list.map((item, index) => {
                /**
                 *  在react中做循环渲染的时候，需要给渲染出的每一项增加一个key值，这个key值每一项都应该不同，是每一项的标识符
                 *  在这里暂时使用index作为key值，但在实际开发中，使用index 做key值是一个非常不好的习惯
                 *
                 *  删除功能：在生成li标签的时候，可以给每一个list标签绑定一个事件,点击的时候，要获取到下标的值,可以通过bind这个函数增加传递参数
                 */
                return (
                    <TodoItem
                        key={index}
                        item={item}
                        index={index}
                        //父组件通过属性传值把自己的一个方法传给了子组件
                        deleteItem={this.handleItemDelete.bind(this)}
                    />
                )
            }
        )
    }

    handleInputChange(e) {
        //在react中，如果你想改变状态，不能通过引用的方法
        //react给每一个组件提供了一个方法 setState() ，向里面传入一个对象的形式，对state里面具体的数据项进行变更
        // this.setState({
        //     inputValue: e.target.value
        // })
        /**
         * 先版本推荐写法，将对象替换成函数，函数直接返回一个对象
         */
        /*   this.setState(() => {
               return {
                   inputValue: e.target.value
               }
           })  */
        /**
         * 新版本推荐写法+ES6写法,当有一个 （）的时候，表示要返回里面的对象,异步的设置数据
         *
         */
        const value = e.target.value;
        this.setState(() => ({
            inputValue: value
        }))
    }

    handleBtnClick() {
        // this.setState({
        //     //ES6里面的一个展开运算符，...this.state.list表示把原有内容拿出来，与后面的元素合并生成一个新的数组
        //     list: [...this.state.list, this.state.inputValue],
        //     inputValue: ''
        // });
        /**
         * setState 里面传入的函数可以接受一个参数prevState，表示修改数据之前的那一次的数据是什么样的，等价于this.state
         */

        this.setState((prevState) => ({
            //ES6里面的一个展开运算符，...this.state.list表示把原有内容拿出来，与后面的元素合并生成一个新的数组
            list: [...prevState.list, prevState.inputValue],
            inputValue: ''
        }));
    }

    handleItemDelete(index) {
        /**
         * 做了数据拷贝
         * immutable（不可变性）
         *  state不允许我们做任何的改变，如果一定要改，那么拷贝一个副本出来，修改副本中的内容
         *  一旦直接修改state里面的内容，那么后面做react性能优化的时候就会有问题
         */
        // const list = [...this.state.list];
        // list.splice(index, 1);
        //不可以直接改变数据，react里面要求你必须要调用setState这个方法
        // this.setState({
        //     list: list
        // });
        // this.setState(() => ({
        //     list
        //     // list: list
        // }));
        this.setState((prevState) => {
            const list = [...prevState.list];
            list.splice(index, 1);
            return {list}
        })
    }
}

export default TodoList;